#pragma once
#include <functional>
#include <atomic>
#include <cstring>
#include <vector>
#include <cstdint>

#include "mpp/rk_mpi.h"
#include "mpp/mpp_mem.h"
#include "mpp/mpp_env.h"
#include "mpp/mpp_time.h"
#include "mpp/mpp_common.h"
#include "mpp/mpp_frame.h"
#include <mpp/mpp_buffer.h>

#include "log/log.h"

typedef struct {
    RK_U32 width;        // 图像水平方向像素数
    RK_U32 height;       // 图像垂直方向像素数
    RK_U32 hor_stride;   // 水平步幅
    RK_U32 ver_stride;   // 垂直步幅
    MppFrameFormat fmt;  // 图像色彩空间格式以及内存排布方式
    MppCodingType type;  // 目标编码类型

    RK_U32 osd_enable;   // 使能OSD调色板
    RK_U32 osd_mode;     // OSD调色板模式
    RK_U32 split_mode;   // 编码器分片模式
    RK_U32 split_arg;    // 分片大小参数
    RK_U32 split_out;    // 分片输出模式

    RK_U32 user_data_enable;  // 制是否启用用户数据（User Data）的传输或处理
    RK_U32 roi_enable;        // 使能ROI测试

    /* rate control runtime parameter */
    RK_S32 fps_in_flex;   // 输入帧率是否可变的标志位
    RK_S32 fps_in_den;    // 输入帧率分母
    RK_S32 fps_in_num;    // 输入帧率分子
    RK_S32 fps_out_flex;  // 输出帧率是否可变的标志位
    RK_S32 fps_out_den;   // 输出帧率分母
    RK_S32 fps_out_num;   // 输出帧率分子
    RK_S32 bps;           // 数据传输的比特率
    RK_S32 bps_max;       // 表示VBR/AVBR模式下的最高码率
    RK_S32 bps_min;       // 表示VBR/AVBR模式下的最低码率
    RK_S32 rc_mode;       // 码率控制模式
    RK_S32 gop_mode;      // 画面组模式
    RK_S32 gop_len;       // 表示Group Of Picture 即两个I帧之间的间隔
    RK_S32 vi_len;        // 表示虚拟I帧和P帧的QP差值

    /* general qp control */
    RK_S32 qp_init;      // 表示初始QP值 QP(Quantization parameter):量化参数
    RK_S32 qp_max;       // 表示P、B帧的最大QP值
    RK_S32 qp_max_i;     // 表示I帧的最大QP值
    RK_S32 qp_min;       // 表示P、B帧的最小QP值
    RK_S32 qp_min_i;     // 表示I帧的最小QP值
    RK_S32 qp_max_step;  // 表示相临两帧之间的帧级QP变化幅度
    RK_S32 qp_delta_ip;  // 表示I帧和P帧的QP差值
    RK_S32 qp_delta_vi;  // 表示虚拟I帧和P帧的QP差值

    RK_U32 constraint_set;  // 定义视频流应该遵守的约束集合
    RK_U32 rotation;        // 定义视频帧的旋转角度
    RK_U32 mirroring;       // 定义视频帧是否应该进行镜像处理
    RK_U32 flip;            // 定义视频帧是否应该进行翻转处理

    MppEncHeaderMode header_mode;  // 定义编码器输出视频流的头部模式
    MppEncSeiMode sei_mode;        // 定义编码器输出中的SEI（补充增强信息）模式
} enc_para_t;

class SmartMppEncoder {
public:
    SmartMppEncoder() {};
	SmartMppEncoder(enc_para_t& enc_para) {
        init(enc_para);
    };
	~SmartMppEncoder() {
        deinit();
    };

    int init(enc_para_t& enc_para);
    int deinit();

    int get_enc_header(std::vector<uint8_t>& date);

    int sync_encode(uint8_t* p_put_data, uint32_t put_data_len, std::vector<uint8_t>& get_data) {
        return enc_put_frame_get_packet(p_put_data, put_data_len, get_data);
    }

    int asyn_encode_put_frame() {
        return 0;
    }

    int asyn_encode_loop_get_packet(std::function<void(uint8_t *, uint32_t)> callback) {
        return 0;
    }

    int asyn_encode_stop() {
        return 0;
    }

private:
    int init_enc_para(enc_para_t& enc_para);
    int setup_enc_cfg();

    int asyn_put_enc_frame(std::vector<uint8_t>& data);
    int loop_asyn_get_enc_packet(std::function<void(uint8_t *, uint32_t)> callback);

    int enc_put_frame_get_packet(uint8_t* p_put_data,uint32_t put_data_len, std::vector<uint8_t>& get_data);
    
private:
    enc_para_t m_enc_para{0};
    std::atomic_bool m_loop_run{false};

    MppCtx m_mpp_ctx{NULL};   // 实例上下文封装
    MppApi* m_mpp_mpi{NULL};  // MPP的对外API接口
    MppEncCfg m_cfg = NULL;     // 编码器信息配置

    // input / output
    MppBufferGroup m_buf_grp = NULL;
    MppBuffer m_frm_buf = NULL;
    MppBuffer m_pkt_buf = NULL;
    MppBuffer m_md_info = NULL;

    // resources
    size_t m_header_size;  // 视频流头部的大小
    size_t m_mdinfo_size;  // 视频流或帧关联的元数据的大小
    size_t m_frame_size;   // 一个视频帧的大小
    size_t m_packet_size;  // 一个数据包的大小 NOTE: packet buffer may overflow
};
